'''
@Description: In User Settings Edit
@Author: your name
@Date: 2019-07-09 10:22:38
@LastEditTime : 2019-12-20 14:48:21
@LastEditors  : Please set LastEditors
'''

import calendar
import datetime
import hashlib
import json
import os
import random
import re
import time
import urllib
import urllib.request
import uuid
from abc import ABCMeta, abstractmethod
from enum import Enum

# import cv
import exifread
import qrcode
import requests
from PIL import Image, ImageDraw, ImageFont

from server.pao_python.pao.service.data.mongo_db import (AggregationOperators,
                                                         C, F, MongoFilter,
                                                         MongoService, N,
                                                         as_date)

from ..pao_python.pao.data import (
    data_to_string_date, get_cur_time, get_date, get_string_to_date,
    string_to_date, string_to_date_only)
from ..pao_python.pao.remote import ErrorCode, JsonRpc2Error
from ..pao_python.pao.service.security.security_utility import \
    get_current_account_id

# from .buss_pub.security_login import get_current_organization_id


# 获取32位随机数
def get_rank_num():
    # 会暴露mac地址，但是一定唯一
    return ''.join(str(uuid.uuid1()).split('-'))

# 获取签名算法


def get_sign(dic):
    lst = list(dic)
    lst.sort()
    arr = []
    for i in lst:
        if i == "sign" or (not dic[i]) or dic[i] == '':
            continue
        arr.append(i+"="+str(dic[i]))
    dic_str = '&'.join(arr)
    return dic_str

# 计算签名


def cal_sign(sign_dict, key):
    str_tmp = get_sign(sign_dict)+"&key="+key
    print(str_tmp)
    md5 = hashlib.md5()  # 获取一个MD5的加密算法对象
    md5.update(str_tmp.encode('utf-8'))  # 得到MD5消息摘要
    md5_digest = md5.hexdigest()  # 以16进制返回消息摘要，32位
    return md5_digest.upper()


def execute_python(valuation_formula, options, option_key='name', option_value='value'):
    ''' 执行Python字符串方法'''
    names = locals()
    total = 0
    for option in options:
        names[str(option[option_key])] = option[option_value]
    try:
        total = eval(valuation_formula, names)
    except Exception as e:
        print(e)
        total = 0
    return total


def get_month_first_day_and_last_day(year=None, month=None):
    """
    :param year: 年份，默认是本年，可传int或str类型
    :param month: 月份，默认是本月，可传int或str类型
    :return: firstDay: 当月的第一天，datetime.date类型
              lastDay: 当月的最后一天，datetime.date类型
    """
    if year:
        year = int(year)
    else:
        year = datetime.date.today().year

    if month:
        month = int(month)
    else:
        month = datetime.date.today().month

    # 获取当月第一天的星期和当月的总天数
    firstDayWeekDay, monthRange = calendar.monthrange(year, month)

    # 获取当月的第一天
    firstDay = datetime.date(year=year, month=month,
                             day=1).strftime('%Y-%m-%d')
    lastDay = datetime.date(year=year, month=month,
                            day=monthRange).strftime('%Y-%m-%d')

    return {'first': firstDay, 'last': lastDay}

# def get_cur_year():
#     year = datetime.date.today().year
#     return year


def get_cur_month():
    month = datetime.date.today().month
    return month


def find_data(db, cols_name, data):
    cols = db[cols_name]
    return list(cols.find(data)[:])


def insert_data(db, cols_name, data):
    cols = db[cols_name]
    print(cols_name, '表插入成功')
    return cols.insert_one(data).inserted_id


def insert_many_data(db, cols_name, datas):
    cols = db[cols_name]
    print(cols_name, '表插入成功')
    return cols.insert_many(datas)


def update_data(db, cols_name, data, condfidition):
    cols = db[cols_name]
    print(cols_name, '表更新成功')
    # print(cols.update_one(condfidition,{'$set':data}).modified_count,'更新结果')
    return cols.update_one(condfidition, {'$set': data}).modified_count == 1


def delete_data(db, cols_name, confidition):
    cols = db[cols_name]
    print(cols_name, '表删除成功')
    return cols.delete_many(confidition).deleted_count > 0


def get_condition(condition):

    for key in list(condition.keys()):
        if not condition.get(key):
            del condition[key]
        else:
            if key in ['handle_code', 'handle_name']:
                new_handle_name = re.compile(condition[key])
                condition[key] = new_handle_name
            if key == 'create_date':
                start = string_to_date(condition[key]+' 00:00:00')
                date = {'$gte': start, '$lt': start +
                        datetime.timedelta(days=1)}
                # date = string_to_date_only(condition[key])
                condition[key] = date

    return condition


def get_info(data, session):
    if 'organization_id' not in data.keys() or ('organization_id' in data.keys() and data['organization_id'] == ''):
        data['organization_id'] = get_current_organization_id(
            session)  # session[SecurityConstant.organization]
    if 'id' not in data.keys():
        data['id'] = get_random_id()
        data['create_date'] = get_cur_time()
    data['modify_date'] = get_cur_time()
    return data


def get_random_id():
    '''生成随机id'''
    return str(uuid.uuid1())

# 获取单据编码(# 用时间戳+GUID的前4位)


def get_code():
    return (get_cur_time().strftime("%Y%m%d%H%M%S") + str(uuid.uuid1())[0:4])

##################################session相关部分################################################


class LoginType():
    account = 'account'
    wechat = 'wechat'


class UserType:
    ''' 人员类型

    Attribute:
        Personnel           人员
        Organizational      组织机构
    '''
    Personnel = '1'
    Organizational = '2'


class SecurityConstant:
    '''安全常量
    Attribute:
    user     ---     Session关键字：当前用户ID
    indentify   ---     Session关键字：存储验证码
    '''

    user = 'user_id'
    indentify = 'indentify'
    role = 'role_id'
    area = 'area_id'
    organization = 'organization_id'


def set_current_user_id(session, user_id):
    '''设置当前用户ID'''
    session[SecurityConstant.user] = user_id


def set_indentify_id(session, indentify_code):
    '''设置验证码'''
    session[SecurityConstant.indentify] = indentify_code


def set_current_role_id(session, role_id):
    '''设置当前角色ID'''
    session[SecurityConstant.role] = role_id


def set_current_area_id(session, area_id):
    '''设置当前用户所在的区域ID'''
    session[SecurityConstant.area] = area_id


def set_current_org_id(session, org_id):
    '''设置当前用户所在的机构ID'''
    session[SecurityConstant.organization] = org_id


def get_indentify_id(session):
    '''获取验证码'''
    try:
        # return session[SecurityConstant.indentify]
        return '1234'
    except:
        raise JsonRpc2Error(ErrorCode.NO_LOGIN,
                            ErrorCode.NO_LOGIN, {'code': '-36006'})

# 获取当前是否登录


def get_user_id_or_false(session):
    '''获取当前用户ID'''
    try:
        # return session[SecurityConstant.user]
        return '23b3630a-d92c-11e9-8b9a-983b8f0bcd67'
        # 坐席用户id
        # return '23b3630a-d92c-11e9-8b9a-983b8f0bcd67'
        # 谷丰用户
        # return '60e35790-15af-11ea-8558-005056882303'
        # 双鸭山
        # return '8bf5b928-f181-11e9-adce-144f8a6221df'
        # 测试
        # return 'be17776c-1d81-11ea-bf1e-144f8ab4d565'
        # 九江超管
        # return '002b6f68-0bf9-11ea-8a46-144f8ab4d565'
        # 九江财务
        # return 'e99f7484-15c6-11ea-9091-9582b69ea449'
    except:
        return False


def get_current_user_id(session):
    '''获取当前用户ID'''
    try:
        # return session[SecurityConstant.user]
        # 坐席用户id
        return '23b3630a-d92c-11e9-8b9a-983b8f0bcd67'
        # 谷丰超管
        # return '60e35790-15af-11ea-8558-005056882303'
        # 双鸭山
        # return '8bf5b928-f181-11e9-adce-144f8a6221df'
        # 测试
        # return 'be17776c-1d81-11ea-bf1e-144f8ab4d565'
        # 九江超管
        # return '002b6f68-0bf9-11ea-8a46-144f8ab4d565'
        # 九江财务
        # return 'e99f7484-15c6-11ea-9091-9582b69ea449'
    except:
        raise JsonRpc2Error(ErrorCode.NO_LOGIN,
                            ErrorCode.NO_LOGIN, {'code': '-36006'})


def get_current_role_id(session):
    '''获取当前用户登录的角色ID'''
    try:
        # return session[SecurityConstant.role]
        # 平台坐席人员id
        # return '295593c2-2088-11ea-99a9-005056882303'
        # 管理员角色id
        return '8ed260f6-e355-11e9-875e-a0a4c57e9ebe'
        # 谷丰工作人员管理员
        # return '8f72e614-e355-11e9-a8b8-a0a4c57e9ebe'
        # 工作人员
        # returm '8e5203ca-e355-11e9-b94c-a0a4c57e9ebe'
        # 双鸭山超级管理员
        # return '8eaf3fba-e355-11e9-b97e-a0a4c57e9ebe'
        # 测试
        # return 'a8a80ae3-1d7d-11ea-b60b-144f8ab4d565'
        # 九江超管
        # return 'dc7d6a7b-1fe7-11ea-bbba-144f8ab4d565' # 本地
        # return '755b8002-fbb0-11e9-a7fa-144f8a6221df' # 测试
        # 九江财务
        # return 'e99f2697-15c6-11ea-b559-9582b69ea449'
    except:
        raise JsonRpc2Error(ErrorCode.NO_LOGIN,
                            ErrorCode.NO_LOGIN, {'code': '-36006'})


def get_current_organization_id(session):
    '''获取当前用户登录的角色所属账户ID,user_id'''
    try:
        # return session[SecurityConstant.organization]
        # 平台
        return '7e7e2fec-d91d-11e9-8e1d-983b8f0bcd67'
        # 谷丰机构
        # return '105df5ac-0301-11ea-9fd1-005056882303'
        # 双鸭山
        # return '0b96b62e-e363-11e9-93c4-a0a4c57e9eb1'
        # 测试
        # return '35660362-1d7d-11ea-809c-144f8ab4d565'
        # 九江超管
        # return 'dab486e2-d08d-11e9-90bb-144f8aec0be5'
        # 九江财务
        # return 'dab486e2-d08d-11e9-90bb-144f8aec0be5'
    except:
        raise JsonRpc2Error(ErrorCode.NO_LOGIN,
                            ErrorCode.NO_LOGIN, {'code': '-36006'})
################################################################################################
# def get_dict(data):
#     respCmtJson = re.sub(r"(,?)(\w+?)\s+?:", r"\1'\2' :", data)
#     respCmtJson = respCmtJson.replace("'", "\"")
#     cmtDict = json.loads(respCmtJson)
#     return cmtDict


class PeriodicityType(Enum):
    '''周期性类型枚举值'''
    # 自然年
    year = 9999
    # 自然月
    month = 9998
    # 自然周
    week = 9997


def get_date_slot(periodicity, choice_date=None):
    '''根据周期性类型返回日期段'''
    res = {}
    print(periodicity, 'periodicity>>>>')

    if periodicity == PeriodicityType.year.value:
        year = datetime.date.today().year
        if choice_date != None:
            year = choice_date.year
        day_begin = datetime.date(year=year, month=1,
                                  day=1).strftime('%Y-%m-%d')
        day_end = datetime.date(year=year, month=12,
                                day=31).strftime('%Y-%m-%d')
    elif periodicity == PeriodicityType.month.value:
        month = None
        if choice_date != None:
            month = choice_date.month
        day = get_month_first_day_and_last_day(None, month)
        day_begin = day['first']
        day_end = day['last']
    elif periodicity == PeriodicityType.week.value:
        date_now = datetime.date.today()
        if choice_date != None:
            date_now = choice_date
        day_begin, day_end = date_now, date_now
        one_day = datetime.timedelta(days=1)
        while day_begin.weekday() != 0:
            day_begin -= one_day
        while day_end.weekday() != 6:
            day_end += one_day
    else:
        date_now = datetime.date.today()
        if choice_date != None:
            date_now = choice_date
        day_begin = date_now.strftime("%Y-%m-%d")
        print(day_begin, 'day_begin>>>>')
        day_end = (date_now +
                   datetime.timedelta(days=periodicity)).strftime('%Y-%m-%d')
        print(day_end, 'day_end>>>>>>')
    res['begin_date'] = day_begin
    res['end_date'] = day_end
    return res


def qr_code(self, web_path, upload_file, handle_code, logo):
    qr = qrcode.QRCode(
        version=1,
        error_correction=qrcode.constants.ERROR_CORRECT_L,
        box_size=10,
        border=2,
    )
    # 添加数据
    qr.add_data("http://192.168.97.135:3000/sign-analysis?key="+handle_code)
    # 填充数据
    qr.make(fit=True)
    # 生成图片
    img = qr.make_image(fill_color="black", back_color="white")
    img = img.convert("RGBA")  # CMYK
    # 获取图片的宽高
    # img_w, img_h = img.size
    # # 添加文字
    # font = ImageFont.truetype("micross.ttf", 20)
    # n = ImgText(handle_code, img, int(img_w * 0.8), font)
    # ''' 获取文字换行后高度 '''
    # note_height = n.get_note_height()
    # line_count = n.get_line_count()
    # char_width = n.get_char_width()
    # print(char_width)
    ''' 根据最终高度绘制新的图片 '''
    # new_img_h = img_h+note_height
    # note_img = Image.new(
    #     "RGBA", (img_w, new_img_h), (255, 255, 255, 255))
    # # ''' 把二维码和文字放入其中 '''
    # note_img.paste(img, (0, 0))
    # n = ImgText(handle_code, note_img,
    #             int(img_w * 0.8), font, (0, 0, 0, 255))
    # text_w = int((img_w - int(img_w * 0.8)) / 2)
    # if line_count == 1:
    #     text_w = int((img_w - char_width) / 2)
    # img = n.draw_text(text_w, img_h-10)

    # 添加logo
    # if logo:
    #     icon = Image.open((web_path+'/'+logo).replace('\\', '/'))
    #     # 重新设置logo的尺寸
    #     icon = icon.resize((120, 120), Image.ANTIALIAS)
    #     w = int((img_w - 120) / 2)
    #     h = int((img_h - 120) / 2)
    #     img.paste(icon, (w, h), icon)
    # 显示图片
    upload_path = upload_file + '\\'+handle_code  # 以标识码命名文件
    file_path = (web_path+'/'+upload_path).replace('\\', '/')
    if not os.path.exists(file_path):  # 不存在改目录则会自动创建
        os.makedirs(file_path)
    img.save(os.path.join(file_path, handle_code.replace(
        '/', '-')+'.png').replace('\\', '/'))
    # 拼接文件url地址
    result = {'code': 200, 'desc': '上传成功', }
    result['url'] = os.path.join(upload_path, handle_code.replace(
        '/', '-')+'.png').replace('\\', '/')
    return result


class ImageSize():
    '''修改身份证读取的图片尺寸和大小'''

    def __init__(self, infile, outfile, mb=18, step=10, quality=80, reset_s=300):
        """不改变图片尺寸压缩到指定大小
        :param infile: 压缩源文件
        :param outfile: 压缩文件保存地址
        :param mb: 压缩目标，KB
        :param step: 每次调整的压缩比率
        :param quality: 初始压缩比率
        :param reset_s: 设置的像素宽度
        """
        self.infile = infile
        self.mb = mb
        self.outfile = outfile
        self.step = step
        self.quality = quality
        self.reset_s = reset_s

    def get_size(self):
        # 获取文件大小:KB
        size = os.path.getsize(self.infile)
        return size / 1024

    def get_outfile(self):
        '''拼接图片保存路径'''
        if self.outfile:
            return self.outfile
        dir, suffix = os.path.splitext(self.infile)
        outfile = '{}-out{}'.format(dir, suffix)
        return outfile

    def compress_image(self):
        '''压缩图片大小'''
        o_size = self.get_size()
        if o_size <= self.mb:
            return self.infile
        outfile = self.get_outfile()
        while o_size > self.mb:
            im = Image.open(self.infile)
            im.save(outfile, quality=self.quality)
            if self.quality - self.step < 0:
                break
            self.quality -= self.step
            o_size = self.get_size()
        return self.outfile, self.get_size()

    def resize_image(self):
        """修改图片尺寸
        """
        im = Image.open(self.infile)
        x, y = im.size
        y_s = int(y * self.reset_s / x)
        out = im.resize((self.reset_s, y_s), Image.ANTIALIAS)
        outfile = self.get_outfile()
        out.save(outfile)

    # @staticmethod
    # def to_jpg(PngPath):
    #     img = cv.imread(PngPath, 0)
    #     w, h = img.shape[::-1]
    #     infile = PngPath
    #     if os.path.splitext(infile)[1] == 'png' or os.path.splitext(infile)[1] == 'PNG':
    #         return PngPath
    #     outfile = os.path.splitext(infile)[0] + ".jpg"
    #     img = Image.open(infile)
    #     img = img.resize((int(w / 2), int(h / 2)), Image.ANTIALIAS)
    #     try:
    #         if len(img.split()) == 4:
    #             r, g, b, a = img.split()
    #             img = Image.merge("RGB", (r, g, b))
    #             img.convert('RGB').save(outfile, quality=100)
    #             os.remove(PngPath)
    #         else:
    #             img.convert('RGB').save(outfile, quality=100)
    #             os.remove(PngPath)
    #         return outfile
    #     except Exception as e:
    #         print("转换JPG 错误", e)


class GetInformationByIdCard():
    '''根据18位身份证获取出生年月、年龄、性别'''

    def __init__(self, id):
        self.id = id
        self.birth_year = int(self.id[6:10])
        self.birth_month = int(self.id[10:12])
        self.birth_day = int(self.id[12:14])

    def get_birthday(self):
        """通过身份证号获取出生日期"""
        birthday = "{0}-{1}-{2}".format(self.birth_year,
                                        self.birth_month, self.birth_day)

        return birthday

    def get_sex(self):
        """男：1 女：2"""
        num = int(self.id[16:17])
        if num % 2 == 0:
            return '女'
        else:
            return '男'

    def get_age(self):
        """通过身份证号获取年龄"""
        now = (datetime.datetime.now() + datetime.timedelta(days=1))
        year = now.year
        month = now.month
        day = now.day

        if year == self.birth_year:
            return 0
        else:
            if self.birth_month > month or (self.birth_month == month and self.birth_day > day):
                return year - self.birth_year - 1
            else:
                return year - self.birth_year

    @staticmethod
    def check_idcard(idcard):
        '''身份证校验'''
        Errors = ['验证通过!', '身份证号码位数不对!',
                  '身份证号码出生日期超出范围或含有非法字符!', '身份证号码校验错误!', '身份证地区非法!']
        area = {"11": "北京", "12": "天津", "13": "河北", "14": "山西", "15": "内蒙古", "21": "辽宁", "22": "吉林", "23": "黑龙江", "31": "上海", "32": "江苏", "33": "浙江", "34": "安徽", "35": "福建", "36": "江西", "37": "山东", "41": "河南", "42": "湖北",
                "43": "湖南", "44": "广东", "45": "广西", "46": "海南", "50": "重庆", "51": "四川", "52": "贵州", "53": "云南", "54": "西藏", "61": "陕西", "62": "甘肃", "63": "青海", "64": "宁夏", "65": "新疆", "71": "台湾", "81": "香港", "82": "澳门", "91": "国外"}
        idcard = str(idcard)
        idcard = idcard.strip()
        idcard_list = list(idcard)
        # 地区校验
        if(not area[(idcard)[0:2]]):
            return (Errors[4])
        # 15位身份号码检测
        if(len(idcard) == 15):
            if((int(idcard[6:8])+1900) % 4 == 0 or((int(idcard[6:8])+1900) % 100 == 0 and (int(idcard[6:8])+1900) % 4 == 0)):
                ereg = re.compile(
                    '[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}$')  # //测试出生日期的合法性
            else:
                ereg = re.compile(
                    '[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}$')  # //测试出生日期的合法性
            if(re.match(ereg, idcard)):
                return (Errors[0])
            else:
                return (Errors[2])
        # 18位身份号码检测
        elif(len(idcard) == 18):
            # 出生日期的合法性检查
            if(int(idcard[6:10]) % 4 == 0 or (int(idcard[6:10]) % 100 == 0 and int(idcard[6:10]) % 4 == 0)):
                # //闰年出生日期的合法性正则表达式
                ereg = re.compile(
                    '[1-9][0-9]{5}(19[0-9]{2}|20[0-9]{2})((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}[0-9Xx]$')
            else:
                # //平年出生日期的合法性正则表达式
                ereg = re.compile(
                    '[1-9][0-9]{5}(19[0-9]{2}|20[0-9]{2})((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}[0-9Xx]$')
            # //测试出生日期的合法性
            if(re.match(ereg, idcard)):
                # //计算校验位
                S = (int(idcard_list[0]) + int(idcard_list[10])) * 7 + (int(idcard_list[1]) + int(idcard_list[11])) * 9 + (int(idcard_list[2]) + int(idcard_list[12])) * 10 + (int(idcard_list[3]) + int(idcard_list[13])) * 5 + (int(
                    idcard_list[4]) + int(idcard_list[14])) * 8 + (int(idcard_list[5]) + int(idcard_list[15])) * 4 + (int(idcard_list[6]) + int(idcard_list[16])) * 2 + int(idcard_list[7]) * 1 + int(idcard_list[8]) * 6 + int(idcard_list[9]) * 3
                Y = S % 11
                M = "F"
                JYM = "10X98765432"
                M = JYM[Y]  # 判断校验位
                if(M == idcard_list[17]):  # 检测ID的校验位
                    return (Errors[0])
                else:
                    return (Errors[3])
            else:
                return (Errors[2])
        else:
            return (Errors[1])


class SerialNumberType(Enum):
    '''流水号枚举值'''
    # 订单流水号类型
    order = 'order'
    # 活动类型流水号
    activity_type = 'activity_type'
    # 行政区划流水号
    administration_division = 'admin_division'


def get_serial_number(db, serial_type):
    '''获取类型的最新流水号'''
    serial_value = ''
    serial_mes = find_data(db, 'PT_Serial_Number', {'type': serial_type})
    if len(serial_mes) > 0:
        number = str(serial_mes[0]['number'])
        max_length = serial_mes[0]['max_length']
        random_length = max_length - len(number)
        base_str = '0123456789'
        length = len(base_str) - 1
        random_str = ''
        if random_length >= 0:
            for i in range(random_length):
                random_str += base_str[random.randint(0, length)]
            serial_value = random_str + number
        elif random_length < 0:
            serial_value = number
        serial_mes[0]['number'] = serial_mes[0]['number'] + 1
        update_data(db, 'PT_Serial_Number', serial_mes[0], {
                    'id': serial_mes[0]['id']})
    else:
        serial_value = get_random_id()
    return serial_value


def operation_result(isSuccess):
    '''新增/编辑成功or失败'''
    return ReturnValue.success.value if isSuccess else ReturnValue.fail.value


class ReturnValue(Enum):
    success = 'Success'
    fail = 'Fail'


def get_area_id(self, _filter):
    admin_area_id = ''
    org_id = get_current_organization_id(self.session)
    _filter.match_bill(C('id') == org_id) \
           .project({'_id': 0})
    res = self.query(_filter, 'PT_User')
    if len(res):
        admin_area_id = res[0]['admin_area_id']
    else:
        raise JsonRpc2Error('-36012', '找不到当前组织机构')
    return admin_area_id


def rang_time(_filter, start_date, end_date):
    _filter.match_bill((
        ((C('start_date') <= start_date)
         & (C('end_date') >= end_date))
        | ((C('start_date') >= start_date) & (C('end_date') <= end_date))
        | ((C('start_date') >= start_date) & (C('start_date') <= end_date))
        | ((C('end_date') >= start_date) & (C('end_date') <= end_date))))
    return _filter


def getAddBillSession():
    return {
        "user_id": '23b3630a-d92c-11e9-8b9a-983b8f0bcd67',
        'organization_id': '7e7e2fec-d91d-11e9-8e1d-983b8f0bcd67'
    }


class Observer():
    __metaclass__ = ABCMeta

    def __init__(self, name, sub):
        pass

    @abstractmethod
    def update(self, condition=None):
        pass


class Subject():
    __metaclass__ = ABCMeta
    observers = []
    @abstractmethod
    def attach(self, observer):
        pass

    @abstractmethod
    def detach(self, observer):
        pass

    @abstractmethod
    def notify(self, condition):
        pass


class WechatSubject(Subject):
    out_trade_no = ''

    def __init__(self):
        pass

    def attach(self, observer):
        self.observers.append(observer)

    def detach(self, observer):
        self.observers.remove(observer)

    def notify(self, condition):
        for observer in self.observers:
            observer.update(condition)


class ResultData():
    '''返回对象'''

    def __init__(self, code, msg, result):
        '''构造函数'''
        # 返回码
        self.code = code
        # 返回信息
        self.msg = msg
        # 返回内容
        self.result = result

    def to_dict(self):
        return self.__dict__


def date_str_to_date(date):
    ''''格式化日期'''
    return get_string_to_date(data_to_string_date(string_to_date(date)))


def get_img_date(path):
    ''' 获取手机图片信息中的日期 '''
    FIELD = 'EXIF DateTimeOriginal'
    fd = open(path, 'rb')
    tags = exifread.process_file(fd)
    fd.close()
    if FIELD in tags:
        # 获取到的结果格式类似为：2018:12:07 03:10:34
        exif_date = str(tags[FIELD])
        new = []
        for s in exif_date:
            new.append(s)
        new[4] = '-'
        new[7] = '-'
        # 格式转成：2018-12-07 03:10:34
        exif_date = ''.join(new)
        return string_to_date(exif_date)
    else:
        # 图片没有时间的时候默认取当前时间
        return get_cur_time()


def get_url_upload_url(url_path):
    ''' 通过url导入图片 '''
    request = urllib.request.Request(url_path)
    response = urllib.request.urlopen(request)
    get_img = response.read()
    #####保存图片#########
    time_id = 'importProduct'
    file_name = str(int(time.time()))
    upload_path = "{0}\\{1}".format('upload', time_id)  # 以xfxz命名文件
    file_path = os.path.join('build', upload_path).replace('\\', '/')
    if not os.path.exists(file_path):  # 不存在改目录则会自动创建
        os.makedirs(file_path)
    save_path = os.path.join(file_path, file_name+'.jpg').replace(
        '\\', '/')  # windows下路径要转化
    with open(save_path, 'wb') as fp:
        fp.write(get_img)
    return '/'+save_path


def get_string_time(data, format):
    '''返回指定的日期字符串'''
    if isinstance(data, str):
        date_str = data.split('T')
        if len(date_str):
            date_str = date_str[0]
        # 转化成时间
        data = string_to_date(date_str)
    res = data_to_string_date(data, format)
    return res


def get_str_to_age(data):
    '''计算年龄'''
    year = datetime.date.today().year - string_to_date(data).year
    return year
